package com.yeyks.alipay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.yeyks.dal.dao.*;
import com.yeyks.dal.domain.AccountInfo;
import com.yeyks.dal.domain.HotelInfo;
import com.yeyks.dal.domain.OrderInfo;
import com.yeyks.dal.domain.RoomInfo;
import com.yeyks.exception.PermissionInvalidException;
import com.yeyks.exception.TokenInvalidException;
import com.yeyks.model.Ajax.AjaxResponseBody;
import com.yeyks.model.OrderStatus;
import com.yeyks.model.PreOrderInfo;
import com.yeyks.model.PreOrderType;
import com.yeyks.model.em.AccountType;
import com.yeyks.model.em.ResponseStatus;
import com.yeyks.service.AccountService;
import com.yeyks.service.MessageService;
import com.yeyks.service.OrderService;
import com.yeyks.service.PayService;
import com.yeyks.util.Utility;
import com.github.binarywang.wxpay.service.WxPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.yeyks.alipay.AlipayConfig.*;

@RestController
@RequestMapping(value = "/ajax/order/alipay")
public class AlipayController {

    @Autowired
    private AccountInfoMapper accountInfoMapper;

    @Autowired
    private AccountService accountService;

    @Autowired
    private RoomInfoMapper roomInfoMapper;

    @Autowired
    private HotelInfoMapper hotelInfoMapper;

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderService orderService;


    @Autowired
    private PayService payService;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private CouponInfoMapper couponInfoMapper;

    @Autowired
    private UserCouponInfoMapper userCouponInfoMapper;

    @Autowired
    private MessageService messageService;

    private static final Integer mockTotalFee = null;

    public String runAlipay(String orderNo, Integer totalFee) throws IOException {
        AlipayClient alipayClient = new DefaultAlipayClient(
                "https://openapi.alipay.com/gateway.do",
                APPID,
                RSA_PRIVATE_KEY,
                "json",
                CHARSET, ALIPAY_PUBLIC_KEY,
                "RSA2"); //获得初始化的AlipayClient
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request
        alipayRequest.setReturnUrl("http://domain.com/CallBack/return_url.jsp");
        alipayRequest.setNotifyUrl("http://domain.com/CallBack/notify_url.jsp");//在公共参数中设置回跳和通知地址
        alipayRequest.setBizContent("{" +
                " \"out_trade_no\":\"" + orderNo + "\"," +
                " \"subject\":\"test beacon subject\"," +
                " \"product_code\":\"QUICK_WAP_PAY\"," +
                " \"body\":\"test beacon body\"," +
                " \"total_amount\":\"0.01\"" +
                " }");//填充业务参数
        String form="";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return form;
    }

    @ApiIgnore
    @RequestMapping(value = "/preOrder", method = RequestMethod.POST)
    public ResponseEntity<?> preOrder(
            HttpServletRequest request, HttpServletResponse response,
            @RequestParam(name = "token", defaultValue = "", required = true) String token,
            @RequestParam(name = "checkInDate", defaultValue = "", required = true) String checkInDate,
            @RequestParam(name = "checkOutDate", defaultValue = "", required = true) String checkOutDate,
            @RequestParam(name = "subject", defaultValue = "", required = true) String subject,
            @RequestParam(name = "body", defaultValue = "", required = true) String body,
            @RequestParam(name = "code", defaultValue = "", required = true) String code,
            @RequestParam(name = "count", defaultValue = "", required = true) Integer count,
            @RequestParam(name = "remark", defaultValue = "", required = true) String remark,
            @RequestParam(name = "coupon", defaultValue = "", required = true) Integer coupon,
            @RequestParam(name = "sourceType", defaultValue = "wx", required = true) String sourceType,
            OrderInfo param
    ){
        AjaxResponseBody responseBody = new AjaxResponseBody();

        try {
            int orderType = PreOrderType.parse(sourceType);
            boolean usesConfig1 = orderType == PreOrderType.wx || orderType == PreOrderType.h5;

            AccountInfo accountInfo = accountService.token2AccountInfo(token);
            if (accountInfo.getType() != AccountType.User) {
                throw new PermissionInvalidException();
            }

            if (subject == null || subject.isEmpty() ||
                    body == null || body.isEmpty()) {
                throw new InvalidParameterException("subject or body is invalid");
            }

            param.setUserId(accountInfo.getId());
            param.setGmtCreate(new Date());
            param.setGmtModified(new Date());
            if (param.getPaymentMethod() == null) {
                param.setPaymentMethod(0);
            }

            param.setStatus(OrderStatus.prePay);

            RoomInfo roomInfo = roomInfoMapper.selectByPrimaryKey(param.getRoomId());
            if (roomInfo == null) {
                throw new Exception("Cannot find the room information.");
            }

            HotelInfo hotelInfo = hotelInfoMapper.selectByPrimaryKey(roomInfo.getHotelId());
            if (hotelInfo == null) {
                throw new Exception("Cannot find the hotel information.");
            }
            param.setSnapshotHotelName(hotelInfo.getName());
            param.setSnapshotRoomName(roomInfo.getTitle());
            param.setSnapshotRoomPrice(roomInfo.getCurPrice());

            JSONObject hotelPrincipalObj = Utility.toJsonObject(hotelInfo.getPrincipalInfo());


            SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" );
            try {
                if (param.getCheckIn() == null) {
                    param.setCheckIn(sdf.parse(checkInDate));
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
            try {
                if (param.getCheckOut() == null) {
                    param.setCheckOut(sdf.parse(checkOutDate));
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }

            final long daytime = (24 * 60 * 60 * 1000);
            long diff = param.getCheckOut().getTime() - param.getCheckIn().getTime();
            long days = (diff + daytime - 1) / daytime;

            Integer totalFee = (int)days * roomInfo.getCurPrice();
            if (count != null && count != 0) {
                totalFee *= count;
            }

            ////////////////////////////////////////////////////////////////////
            // 优惠券使用逻辑
            if (coupon != null) {
                List<Map> couponInfos = couponInfoMapper.selectByUser(accountInfo.getId(), false, true, coupon);
                if (couponInfos == null && couponInfos.size() == 0) {
                    responseBody.setCode(ResponseStatus.RS_COUPON_USE_ERROR.getCode());
                    responseBody.setMsg(ResponseStatus.RS_COUPON_USE_ERROR.getMsg());

                    return ResponseEntity.ok(responseBody);
                }

                Map couponInfo = couponInfos.get(0);
                Integer validFee = 0, price = 0;
                try {
                    validFee = Integer.parseInt(couponInfo.get("valid_fee").toString());
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                try {
                    price = Integer.parseInt(couponInfo.get("price").toString());
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                /*
                String validHotels = null;
                try {
                    validHotels = couponInfo.get("valid_hotels").toString();
                } catch (Throwable e) {

                }

                Boolean validHotel = true;
                if (!StringUtils.isBlank(validHotels)) {
                    List<Integer> ids = Utility.str2intList(validHotels, "|");
                    if (ids != null && ids.size() != 0) {
                        validHotel = false;
                        for (Integer id : ids) {
                            if (id.intValue() == hotelInfo.getId().intValue()) {
                                validHotel = true;
                                break;
                            }
                        }
                    }
                }

                if (!validHotel) {
                    responseBody.setCode(ResponseStatus.RS_COUPON_USE_NOTSUPPORT.getCode());
                    responseBody.setMsg(ResponseStatus.RS_COUPON_USE_NOTSUPPORT.getMsg());

                    return ResponseEntity.ok(responseBody);
                }
                */
                if (validFee != 0 && validFee > totalFee) {
                    responseBody.setCode(ResponseStatus.RS_COUPON_USE_VALIDFEE.getCode());
                    responseBody.setMsg(ResponseStatus.RS_COUPON_USE_VALIDFEE.getMsg());

                    return ResponseEntity.ok(responseBody);
                }

                if (price > totalFee) {
                    totalFee = 1;
                } else {
                    totalFee -= price;
                }

                /////////////////////////////////
                int rec = userCouponInfoMapper.updateUsed(coupon);
                if (rec == 0) {
                    throw new Exception("updated 0 row.");
                }
            }
            ////////////////////////////////////////////////////////////////////

            JSONObject orderExtraObject = Utility.toJsonObject(param.getExtraInfo());
            orderExtraObject.put("snapshot_hotel_address", hotelInfo.getAddress());
            orderExtraObject.put("snapshot_hotel_id", hotelInfo.getId());
            orderExtraObject.put("snapshot_hotel_phone", hotelPrincipalObj.getString("phone"));
            orderExtraObject.put("snapshot_pcinfo", accountService.getPrecentage());
            orderExtraObject.put("snapshot_totalfee", totalFee);
            orderExtraObject.put("snapshot_days", days);
            orderExtraObject.put("snapshot_count", count);
            orderExtraObject.put("remark", remark);
            param.setSnapshotTotalFee(totalFee);
            param.setExtraInfo(orderExtraObject.toJSONString());

            String orderNo = new Date().getTime() + Utility.randomString(7);
            param.setOrderNo(orderNo);

            if (mockTotalFee != null) {
                totalFee = mockTotalFee;
            } else if (accountInfo.getPhone().equals("18611699741")) {
                totalFee = 1;
            }


            String alipayInfo = runAlipay(orderNo, totalFee);

            PreOrderInfo preOrderInfo = new PreOrderInfo();
            //preOrderInfo.setCharge(charge.toString());
            preOrderInfo.setAccountInfo(accountInfo);
            preOrderInfo.setOrderInfo(param);
            preOrderInfo.setRoomInfo(roomInfo);
            preOrderInfo.setHotelInfo(hotelInfo);
            preOrderInfo.setDays(days);
            preOrderInfo.setAlipayInfo(alipayInfo);
            preOrderInfo.setAlipay(true);
            orderService.insertPreOrder(preOrderInfo);

            responseBody.setBody(preOrderInfo);

            responseBody.setCode(ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(ResponseStatus.RS_SUCCESS.getMsg());
        } catch (TokenInvalidException e) {
            responseBody.setCode(ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(ResponseStatus.RS_FAIL_INVALID_TOKEN.getMsg());
        } catch (InvalidParameterException e) {
            responseBody.setCode(ResponseStatus.RS_FAIL_INVALID_TOKEN.getCode());
            responseBody.setMsg(e.getMessage());
        } catch (PermissionInvalidException e) {
            responseBody.setCode(ResponseStatus.RS_FAIL_INVALID_PERMISSION.getCode());
            responseBody.setMsg(ResponseStatus.RS_FAIL_INVALID_PERMISSION.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }

        return ResponseEntity.ok(responseBody);
    }

}
